"""
CTP期货数据适配器
===============

基于vnpy CTP Gateway的期货数据源适配器，提供实时行情数据接入。
支持期货合约信息查询、实时Tick数据订阅、历史数据查询等功能。

特性：
- CTP期货实时行情接入
- 合约信息自动更新
- 断线自动重连
- 数据质量监控
- 异步数据处理
"""

from typing import Dict, List, Optional, Any
from datetime import datetime, timedelta
import asyncio
import logging
import json
from pathlib import Path

# vnpy相关导入
try:
    from vnpy.event import EventEngine, Event
    from vnpy.trader.engine import MainEngine
    from vnpy.trader.constant import Exchange
    from vnpy.trader.object import TickData, ContractData, SubscribeRequest
    from vnpy.gateway.ctp import CtpGateway
    VNPY_AVAILABLE = True
except ImportError:
    VNPY_AVAILABLE = False
    EventEngine = None
    MainEngine = None
    CtpGateway = None

from ..redfire_gateway.redfire_gateway_adapter import (
    RedFireGatewayAdapter, DataSourceType, ConnectionStatus,
    MarketDataTick, MarketDataBar, ContractInfo
)


class CTPFuturesAdapter(RedFireGatewayAdapter):
    """
    CTP期货数据适配器
    
    基于vnpy的CTP Gateway实现期货数据的实时接入。
    提供标准化的数据接口，支持多合约订阅和数据分发。
    """
    
    def __init__(self, 
                 gateway_name: str = "ctp_futures",
                 config: Dict[str, Any] = None):
        """
        初始化CTP期货适配器
        
        Args:
            gateway_name: 网关名称
            config: CTP连接配置
        """
        if not VNPY_AVAILABLE:
            raise ImportError(
                "vnpy is required for CTP support. "
                "Install with: pip install vnpy"
            )
        
        super().__init__(gateway_name, DataSourceType.CTP_FUTURES, config)
        
        # CTP配置
        self.ctp_config = config or {}
        self.userid = self.ctp_config.get("userid", "")
        self.password = self.ctp_config.get("password", "")
        self.brokerid = self.ctp_config.get("brokerid", "")
        self.td_address = self.ctp_config.get("td_address", "")
        self.md_address = self.ctp_config.get("md_address", "")
        self.appid = self.ctp_config.get("appid", "")
        self.auth_code = self.ctp_config.get("auth_code", "")
        self.product_info = self.ctp_config.get("product_info", "")
        
        # vnpy组件
        self.event_engine: Optional[EventEngine] = None
        self.main_engine: Optional[MainEngine] = None
        self.ctp_gateway: Optional[CtpGateway] = None
        
        # 数据缓存
        self._tick_cache: Dict[str, MarketDataTick] = {}
        self._contract_cache: Dict[str, ContractInfo] = {}
        
        # 异步任务
        self._event_loop_task: Optional[asyncio.Task] = None
        
        self.logger.info(f"CTP期货适配器初始化完成: {gateway_name}")
    
    async def connect(self) -> bool:
        """
        连接CTP期货接口
        
        Returns:
            bool: 连接是否成功
        """
        try:
            await self._on_status_change(ConnectionStatus.CONNECTING)
            self.logger.info("开始连接CTP期货接口...")
            
            # 验证配置
            if not self._validate_config():
                raise ValueError("CTP配置不完整")
            
            # 创建vnpy组件
            await self._create_vnpy_components()
            
            # 启动事件循环
            self._event_loop_task = asyncio.create_task(self._run_event_loop())
            
            # 连接CTP网关
            gateway_setting = {
                "用户名": self.userid,
                "密码": self.password,
                "经纪商代码": self.brokerid,
                "交易服务器": self.td_address,
                "行情服务器": self.md_address,
                "产品名称": self.product_info,
                "授权编码": self.auth_code,
                "产品信息": self.appid
            }
            
            self.main_engine.connect(gateway_setting, self.gateway_name)
            
            # 等待连接完成
            await self._wait_for_connection()
            
            await self._on_status_change(ConnectionStatus.CONNECTED)
            self.logger.info("CTP期货接口连接成功")
            return True
            
        except Exception as e:
            self.logger.error(f"CTP期货接口连接失败: {e}")
            await self._on_status_change(ConnectionStatus.ERROR)
            return False
    
    async def disconnect(self) -> bool:
        """
        断开CTP期货接口连接
        
        Returns:
            bool: 断开是否成功
        """
        try:
            await self._on_status_change(ConnectionStatus.DISCONNECTED)
            
            # 停止事件循环
            if self._event_loop_task and not self._event_loop_task.done():
                self._event_loop_task.cancel()
                try:
                    await self._event_loop_task
                except asyncio.CancelledError:
                    pass
            
            # 断开网关连接
            if self.main_engine:
                self.main_engine.close()
            
            # 清理组件
            self.event_engine = None
            self.main_engine = None
            self.ctp_gateway = None
            
            self.logger.info("CTP期货接口断开成功")
            return True
            
        except Exception as e:
            self.logger.error(f"CTP期货接口断开失败: {e}")
            return False
    
    async def subscribe_tick(self, symbol: str, exchange: str = "") -> bool:
        """
        订阅Tick数据
        
        Args:
            symbol: 合约代码
            exchange: 交易所代码
            
        Returns:
            bool: 订阅是否成功
        """
        try:
            if not self.is_connected():
                self.logger.error("CTP未连接，无法订阅数据")
                return False
            
            # 转换交易所代码
            vnpy_exchange = self._convert_exchange(exchange)
            if not vnpy_exchange:
                self.logger.error(f"不支持的交易所: {exchange}")
                return False
            
            # 创建订阅请求
            subscribe_req = SubscribeRequest(
                symbol=symbol,
                exchange=vnpy_exchange
            )
            
            # 发送订阅请求
            self.main_engine.subscribe(subscribe_req, self.gateway_name)
            
            # 记录订阅
            key = f"{symbol}.{exchange}"
            self._subscribed_symbols[key] = {
                "symbol": symbol,
                "exchange": exchange,
                "type": "tick",
                "subscribed_at": datetime.now()
            }
            
            self.logger.info(f"订阅Tick数据成功: {symbol}@{exchange}")
            return True
            
        except Exception as e:
            self.logger.error(f"订阅Tick数据失败: {symbol}@{exchange}, 错误: {e}")
            return False
    
    async def subscribe_bar(self, symbol: str, exchange: str = "", interval: str = "1m") -> bool:
        """
        订阅K线数据（CTP不直接支持K线订阅，通过Tick数据生成）
        
        Args:
            symbol: 合约代码
            exchange: 交易所代码
            interval: K线周期
            
        Returns:
            bool: 订阅是否成功
        """
        # CTP主要提供Tick数据，K线数据需要通过Tick数据生成
        self.logger.info(f"CTP不直接支持K线订阅，将通过Tick数据生成{interval}K线: {symbol}@{exchange}")
        return await self.subscribe_tick(symbol, exchange)
    
    async def unsubscribe_tick(self, symbol: str, exchange: str = "") -> bool:
        """
        取消订阅Tick数据
        
        Args:
            symbol: 合约代码
            exchange: 交易所代码
            
        Returns:
            bool: 取消订阅是否成功
        """
        try:
            # CTP Gateway通常不支持单独取消订阅
            key = f"{symbol}.{exchange}"
            if key in self._subscribed_symbols:
                del self._subscribed_symbols[key]
            
            self.logger.info(f"取消订阅Tick数据: {symbol}@{exchange}")
            return True
            
        except Exception as e:
            self.logger.error(f"取消订阅Tick数据失败: {symbol}@{exchange}, 错误: {e}")
            return False
    
    async def unsubscribe_bar(self, symbol: str, exchange: str = "", interval: str = "1m") -> bool:
        """
        取消订阅K线数据
        
        Args:
            symbol: 合约代码
            exchange: 交易所代码
            interval: K线周期
            
        Returns:
            bool: 取消订阅是否成功
        """
        return await self.unsubscribe_tick(symbol, exchange)
    
    async def query_contracts(self) -> List[ContractInfo]:
        """
        查询所有合约信息
        
        Returns:
            List[ContractInfo]: 合约信息列表
        """
        try:
            if not self.is_connected():
                self.logger.error("CTP未连接，无法查询合约")
                return []
            
            # 从缓存返回合约信息
            return list(self._contract_cache.values())
            
        except Exception as e:
            self.logger.error(f"查询合约信息失败: {e}")
            return []
    
    async def query_history(self, 
                           symbol: str, 
                           exchange: str = "",
                           start: datetime = None,
                           end: datetime = None,
                           interval: str = "1m") -> List[MarketDataBar]:
        """
        查询历史数据（CTP不直接支持历史数据查询）
        
        Args:
            symbol: 合约代码
            exchange: 交易所代码
            start: 开始时间
            end: 结束时间
            interval: K线周期
            
        Returns:
            List[MarketDataBar]: 历史K线数据
        """
        self.logger.warning("CTP Gateway不支持历史数据查询，请使用其他数据源")
        return []
    
    # vnpy组件管理
    async def _create_vnpy_components(self):
        """创建vnpy组件"""
        # 创建事件引擎
        self.event_engine = EventEngine()
        
        # 创建主引擎
        self.main_engine = MainEngine(self.event_engine)
        
        # 添加CTP网关
        self.main_engine.add_gateway(CtpGateway)
        
        # 注册事件处理器
        self._register_event_handlers()
        
        self.logger.info("vnpy组件创建完成")
    
    def _register_event_handlers(self):
        """注册事件处理器"""
        from vnpy.event import EVENT_TICK, EVENT_CONTRACT, EVENT_LOG
        
        # 注册Tick数据事件
        self.event_engine.register(EVENT_TICK, self._on_vnpy_tick)
        
        # 注册合约数据事件
        self.event_engine.register(EVENT_CONTRACT, self._on_vnpy_contract)
        
        # 注册日志事件
        self.event_engine.register(EVENT_LOG, self._on_vnpy_log)
        
        self.logger.info("事件处理器注册完成")
    
    async def _run_event_loop(self):
        """运行事件循环"""
        try:
            self.event_engine.start()
            self.logger.info("vnpy事件引擎启动")
            
            # 保持事件引擎运行
            while not self._event_loop_task.cancelled():
                await asyncio.sleep(0.1)
                
        except asyncio.CancelledError:
            self.logger.info("事件循环被取消")
        except Exception as e:
            self.logger.error(f"事件循环异常: {e}")
        finally:
            if self.event_engine:
                self.event_engine.stop()
                self.logger.info("vnpy事件引擎停止")
    
    async def _wait_for_connection(self, timeout: int = 30):
        """等待连接完成"""
        start_time = datetime.now()
        
        while (datetime.now() - start_time).seconds < timeout:
            # 检查是否有合约数据，作为连接成功的标志
            if self._contract_cache:
                return True
            await asyncio.sleep(1)
        
        raise TimeoutError(f"连接超时: {timeout}秒")
    
    # vnpy事件处理器
    def _on_vnpy_tick(self, event: Event):
        """处理vnpy Tick事件"""
        try:
            tick_data: TickData = event.data
            
            # 转换为RedFire标准格式
            redfire_tick = self._convert_tick_data(tick_data)
            
            # 缓存数据
            key = f"{redfire_tick.symbol}.{redfire_tick.exchange}"
            self._tick_cache[key] = redfire_tick
            
            # 异步分发数据
            asyncio.create_task(self._on_tick(redfire_tick))
            
        except Exception as e:
            self.logger.error(f"处理vnpy Tick事件失败: {e}")
    
    def _on_vnpy_contract(self, event: Event):
        """处理vnpy合约事件"""
        try:
            contract_data: ContractData = event.data
            
            # 转换为RedFire标准格式
            redfire_contract = self._convert_contract_data(contract_data)
            
            # 缓存合约信息
            key = f"{redfire_contract.symbol}.{redfire_contract.exchange}"
            self._contract_cache[key] = redfire_contract
            
            # 异步分发合约信息
            asyncio.create_task(self._on_contract(redfire_contract))
            
        except Exception as e:
            self.logger.error(f"处理vnpy合约事件失败: {e}")
    
    def _on_vnpy_log(self, event: Event):
        """处理vnpy日志事件"""
        try:
            log_data = event.data
            level = getattr(log_data, 'level', 'INFO')
            msg = getattr(log_data, 'msg', str(log_data))
            
            if level == 'ERROR':
                self.logger.error(f"vnpy: {msg}")
            elif level == 'WARNING':
                self.logger.warning(f"vnpy: {msg}")
            else:
                self.logger.info(f"vnpy: {msg}")
                
        except Exception as e:
            self.logger.error(f"处理vnpy日志事件失败: {e}")
    
    # 数据转换方法
    def _convert_tick_data(self, vnpy_tick: 'TickData') -> MarketDataTick:
        """转换vnpy Tick数据为RedFire格式"""
        return MarketDataTick(
            symbol=vnpy_tick.symbol,
            exchange=self._convert_exchange_reverse(vnpy_tick.exchange),
            datetime=vnpy_tick.datetime,
            last_price=vnpy_tick.last_price,
            open_price=vnpy_tick.open_price,
            high_price=vnpy_tick.high_price,
            low_price=vnpy_tick.low_price,
            pre_close=vnpy_tick.pre_close,
            volume=int(vnpy_tick.volume),
            turnover=vnpy_tick.turnover,
            open_interest=int(vnpy_tick.open_interest),
            bid_prices=[vnpy_tick.bid_price_1, vnpy_tick.bid_price_2, vnpy_tick.bid_price_3, vnpy_tick.bid_price_4, vnpy_tick.bid_price_5],
            bid_volumes=[int(vnpy_tick.bid_volume_1), int(vnpy_tick.bid_volume_2), int(vnpy_tick.bid_volume_3), int(vnpy_tick.bid_volume_4), int(vnpy_tick.bid_volume_5)],
            ask_prices=[vnpy_tick.ask_price_1, vnpy_tick.ask_price_2, vnpy_tick.ask_price_3, vnpy_tick.ask_price_4, vnpy_tick.ask_price_5],
            ask_volumes=[int(vnpy_tick.ask_volume_1), int(vnpy_tick.ask_volume_2), int(vnpy_tick.ask_volume_3), int(vnpy_tick.ask_volume_4), int(vnpy_tick.ask_volume_5)],
            source="ctp",
            gateway=self.gateway_name
        )
    
    def _convert_contract_data(self, vnpy_contract: 'ContractData') -> ContractInfo:
        """转换vnpy合约数据为RedFire格式"""
        return ContractInfo(
            symbol=vnpy_contract.symbol,
            exchange=self._convert_exchange_reverse(vnpy_contract.exchange),
            name=vnpy_contract.name,
            product=vnpy_contract.product.value if hasattr(vnpy_contract.product, 'value') else str(vnpy_contract.product),
            size=int(vnpy_contract.size),
            pricetick=vnpy_contract.pricetick,
            min_volume=int(vnpy_contract.min_volume),
            stop_supported=vnpy_contract.stop_supported,
            net_position=vnpy_contract.net_position,
            history_data=vnpy_contract.history_data,
            source="ctp",
            gateway=self.gateway_name
        )
    
    def _convert_exchange(self, exchange: str) -> Optional['Exchange']:
        """转换交易所代码为vnpy格式"""
        exchange_map = {
            "SHFE": Exchange.SHFE,      # 上海期货交易所
            "DCE": Exchange.DCE,        # 大连商品交易所
            "CZCE": Exchange.CZCE,      # 郑州商品交易所
            "INE": Exchange.INE,        # 上海国际能源交易中心
            "CFFEX": Exchange.CFFEX,    # 中国金融期货交易所
        }
        return exchange_map.get(exchange.upper())
    
    def _convert_exchange_reverse(self, vnpy_exchange: 'Exchange') -> str:
        """转换vnpy交易所格式为字符串"""
        if hasattr(vnpy_exchange, 'value'):
            return vnpy_exchange.value
        return str(vnpy_exchange)
    
    def _validate_config(self) -> bool:
        """验证CTP配置"""
        required_fields = ["userid", "password", "brokerid", "md_address"]
        
        for field in required_fields:
            if not getattr(self, field):
                self.logger.error(f"CTP配置缺失字段: {field}")
                return False
        
        return True
    
    # 健康检查扩展
    async def health_check(self) -> Dict[str, Any]:
        """健康检查"""
        base_health = await super().health_check()
        
        ctp_health = {
            "userid": self.userid,
            "brokerid": self.brokerid,
            "md_address": self.md_address,
            "td_address": self.td_address,
            "cached_ticks": len(self._tick_cache),
            "cached_contracts": len(self._contract_cache),
            "vnpy_event_engine_active": self.event_engine.active if self.event_engine else False,
        }
        
        base_health.update(ctp_health)
        return base_health
